#include "gtest/gtest.h"
#include "../src/include/core.h"
#define SIZE 1000

using namespace std;

// -n 无环
TEST(core_test, gen_chains_all) {
    int len = 4;
    const char *words[] = {"woo", "oom", "moon", "noox"};
    int res_len = 6;
    const char *result[] = {
            "woo oom moon noox",
            "woo oom moon",
            "woo oom",
            "oom moon noox",
            "oom moon",
            "moon noox",
    };
    char **_result = new char * [SIZE];
    int _num = gen_chains_all((char**)words, len, _result);
    EXPECT_EQ(res_len, _num);
    sort(_result, _result + res_len, strcmp);
    for (int i = 0; i < res_len; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

// -w -h无 -t无 -j无 -r无
TEST(core_test, gen_chain_word1) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir","moon", "mooc"};
    int res_num = 4;
    const char *result[] = {"alph", "hand", "dog", "group"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 0, 0, 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-w -h h -t无 -j无 -r无
TEST(core_test, gen_chain_word2) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "moon"};
    int res_num = 3;
    const char *result[] = {"hand", "dog", "group"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 'h', 0, 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


//-w -h无 -t g -j无 -r无
TEST(core_test, gen_chain_word3) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "moon"};
    int res_num = 3;
    const char *result[] = {"alph", "hand", "dog"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **) words, len, _result, 0, 'g', 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-w -h h -t g -j a -r无
TEST(core_test, gen_chain_word4) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "moon"};
    int res_num = 2;
    const char *result[] = {"hand", "dog"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 'h', 'g', 'a', false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


// -w -h无 -t无 -j无 -r有
TEST(core_test, gen_chain_word5) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "element", "than", "apple", "eir", "nop", "pua", "ahead"};
    int res_num = 8;
    const char *result[] = {"apple", "element", "than", "nop", "pua", "alpha", "ahead", "dog"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 0, 0, 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-w -h e -t无 -j无 -r有
TEST(core_test, gen_chain_word6) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "element", "than", "apple", "eir", "nop", "pua", "ahead"};
    int res_num = 7;
    const char *result[] = {"element", "than", "nop", "pua", "alpha", "apple", "eir"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 'e', 0, 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


//-w -h无 -t g -j无 -r有
TEST(core_test, gen_chain_word7) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "element", "than", "apple", "eir", "nop", "pua", "ahead"};
    int res_num = 8;
    const char *result[] = {"apple", "element", "than", "nop", "pua", "alpha", "ahead", "dog"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 0, 'g', 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-w -h e -t g -j a -r有
TEST(core_test, gen_chain_word8) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "element", "than", "apple", "eir", "nop", "pua", "ahead"};
    int res_num = 4;
    const char *result[] = {"element", "than", "nop", "pua"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_word((char **)words, len, _result, 'e', 'a', 'a', true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


// -c -h无 -t无 -j无 -r无
TEST(core_test, gen_chain_char1) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "mooooooooooooooooooooon"};
    int res_num = 2;
    const char *result[] = {"mooooooooooooooooooooon", "nop"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 0, 0, 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-c -h a -t无 -j无 -r无
TEST(core_test, gen_chain_char2) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "mooooooooooooooooooooon"};
    int res_num = 4;
    const char *result[] = {"apple", "element", "than", "nop"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 'a', 0, 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


//-c -h无 -t p -j无 -r无
TEST(core_test, gen_chain_char3) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "mooooooooooooooooooooon"};
    int res_num = 2;
    const char *result[] = {"mooooooooooooooooooooon", "nop"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **) words, len, _result, 0, 'p', 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-c -h a -t n -j m -r无
TEST(core_test, gen_chain_char4) {
    int len = 11;
    const char *words[] = {"apple", "alph", "dog", "hand", "group", "element", "than", "apple", "eir", "nop", "mooooooooooooooooooooon"};
    int res_num = 3;
    const char *result[] = {"apple", "element", "than",};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 'a', 'n', 'm', false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

// -c -h无 -t无 -j无 -r有
TEST(core_test, gen_chain_char5) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "group", "element", "than", "apple", "pua", "nop", "mooooooooooooooooooooon"};
    int res_num = 7;
    const char *result[] = {"mooooooooooooooooooooon", "nop", "pua", "alpha", "apple", "element", "than"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 0, 0, 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-c -h n -t无 -j无 -r有
TEST(core_test, gen_chain_char6) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "group", "element", "than", "apple", "pua", "nop", "mooooooooooooooooooooon"};
    int res_num = 6;
    const char *result[] = {"nop", "pua", "alpha", "apple", "element", "than"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 'n', 0, 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


//-c -h无 -t a -j无 -r有
TEST(core_test, gen_chain_char7) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "group", "element", "than", "apple", "pua", "nop", "mooooooooooooooooooooon"};
    int res_num = 4;
    const char *result[] = {"mooooooooooooooooooooon", "nop", "pua", "alpha"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **) words, len, _result, 0, 'a', 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

//-c -h a -t n -j m -r有
TEST(core_test, gen_chain_char8) {
    int len = 11;
    const char *words[] = {"apple", "alpha", "dog", "hand", "group", "element", "than", "apple", "pua", "nop", "mooooooooooooooooooooon"};
    int res_num = 4;
    const char *result[] = {"alpha", "apple", "element", "than"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 'a', 'n', 'm', true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}


// -----------------------------异常情况测试-----------------------------------

// -n 有环
TEST(core_test, exception1) {
    int len = 4;
    const char *words[] = {"ab", "bc", "cd", "da"};
    char **_result = new char * [SIZE];
    try {
        gen_chains_all((char **) words, len, _result);
    } catch (const std::exception &e) {
        EXPECT_STREQ(e.what(), "The words contain a circle.");
    }
}

// 无-r指令，单词链中有环
TEST(core_test, exception2) {
    int len = 4;
    const char *words[] = {"ab", "bc", "cd", "da"};
    char **_result = new char * [SIZE];
    try {
        gen_chain_word((char **) words, len, _result, 0, 0, 0, false);
    } catch (const std::exception &e) {
        EXPECT_STREQ(e.what(), "The words contain a circle.");
    }
}

// 传入单词长度异常 words.size()为0，或words与len不一致
TEST(core_test, exception4) {
    int len = 0;
    const char *words[] = {"ab", "bc", "cd", "da"};
    char **_result = new char * [SIZE];
    try {
        gen_chains_all((char **) words, len, _result);
    } catch (const std::exception &e) {
        EXPECT_STREQ(e.what(), "Please ensure the words length is greater than zero.");
    }
}
TEST(core_test, exception5) {
    int len = 0;
    const char *words[] = {"ab", "bc", "cd", "da"};
    char **_result = new char * [SIZE];
    try {
        gen_chain_word((char **) words, len, _result, 0, 0, 0, true);
    } catch (const std::exception &e) {
        EXPECT_STREQ(e.what(), "Please ensure the words length is greater than zero.");
    }
}
TEST(core_test, exception6) {
    int len = 0;
    const char **words = nullptr;
    char **_result = new char * [SIZE];
    try {
        gen_chain_char((char **) words, len, _result, 0, 0, 0, true);
    } catch (const std::exception &e) {
        EXPECT_STREQ(e.what(), "Please ensure the words length is greater than zero.");
    }
}

TEST(core_test, test1) {
    int len = 3;
    const char *words[] = {"ahead", "does", "sad"};
    int res_num = 3;
    const char *result[] = {"ahead", "does", "sad"};
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 'a', 0, 0, true);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}

TEST(core_test, test2) {
    int len = 2;
    const char *words[] = {"ahead", "did", };
    int res_num = 2;
    const char *result[] = {"ahead", "did", };
    char **_result = new char *[SIZE];
    int _num = gen_chain_char((char **)words, len, _result, 'a', 0, 0, false);
    EXPECT_EQ(res_num, _num);
    for (int i = 0; i < res_num; i++) {
        EXPECT_STREQ(result[i], _result[i]);
        free(_result[i]);
    }
    free(_result);
}
